package com.jianggujin.demo.admin;

import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import com.jianggujin.demo.admin.handler.Handler;
import com.jianggujin.modulelink.exception.JActionNotFoundException;
import com.jianggujin.modulelink.exception.JModuleNotFoundException;
import com.jianggujin.modulelink.magager.JDefaultModuleManager;
import com.jianggujin.modulelink.magager.JModuleManager;
import com.jianggujin.modulelink.util.JLogFactory;
import com.jianggujin.modulelink.util.JLogFactory.JLog;
import com.jianggujin.modulelink.util.JResolverUtils;
import com.jianggujin.modulelink.util.JStringUtils;

import fi.iki.elonen.NanoHTTPD;
import fi.iki.elonen.util.ServerRunner;

public class App extends NanoHTTPD {

    private JModuleManager manager = null;
    private Map<String, Handler> handlers = new HashMap<String, Handler>();
    private Properties mimeTypes = new Properties();
    private JLog logger = JLogFactory.getLog(App.class);

    public App() throws Exception {
        super(80);
        manager = new JDefaultModuleManager();
        InputStream in = getClass().getClassLoader().getResourceAsStream("mime-type.properties");
        mimeTypes.load(in);
        in.close();
        JResolverUtils utils = new JResolverUtils();
        utils.setClassLoader(getClass().getClassLoader());
        utils.findImplementations(Handler.class, new String[] { "com.jianggujin.demo.admin.handler" });
        for (Class<?> clazz : utils.getClasses()) {
            if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
                continue;
            }
            if (logger.isInfoEnabled()) {
                logger.info("load handler:" + clazz.getName());
            }
            Handler handler = (Handler) clazz.newInstance();
            handlers.put("/" + JStringUtils.firstCharToLowerCase(clazz.getSimpleName()), handler);
        }
    }

    @Override
    public Response serve(IHTTPSession session) {
        String uri = session.getUri();
        if (logger.isInfoEnabled()) {
            logger.info(session.getMethod() + " " + uri);
        }
        if ("/".equals(uri)) {
            uri = "/index.html";
        }
        try {
            Handler handler = handlers.get(uri);
            if (handler != null) {
                return handler.handle(manager, session);
            }
            String path = "http" + uri;
            if (logger.isInfoEnabled()) {
                logger.info("find resource: " + path);
            }
            int index = uri.lastIndexOf(".");
            if (index > 0) {
                String mimeType = this.mimeTypes.getProperty(uri.substring(index + 1));
                if (!JStringUtils.isEmpty(mimeType)) {
                    InputStream in = getClass().getClassLoader().getResourceAsStream(path);
                    if (in != null) {
                        return newChunkedResponse(Response.Status.OK, mimeType, in);
                    }
                }
            }
            return newFixedLengthResponse(Response.Status.NOT_FOUND, NanoHTTPD.MIME_HTML, "Not Found " + uri);
        } catch (JModuleNotFoundException e) {
            return newFixedLengthResponse(Response.Status.NOT_FOUND, NanoHTTPD.MIME_HTML, e.toString());
        } catch (JActionNotFoundException e) {
            return newFixedLengthResponse(Response.Status.NOT_FOUND, NanoHTTPD.MIME_HTML, e.toString());
        } catch (Exception e) {
            logger.error("serve error", e);
            return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_HTML, e.toString());
        }
    }

    public static void main(String[] args) {
        ServerRunner.run(App.class);
    }
}
